﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace WebStudio.Framework.Service
{
    public static class InstallerAPI
    {
        // Fields
        public const int ERROR_INSUFFICIENT_BUFFER = 0x7a;
        public const int GENERIC_READ = -2147483648;
        public const int SERVICE_NO_CHANGE = -1;
        public const int STANDARD_RIGHTS_REQUIRED = 0xf0000;

        // Methods
        [DllImport("advapi32.dll")]
        public static extern bool ChangeServiceConfig(IntPtr hService, ServiceType dwServiceType, ServiceStartType dwStartType, int dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, int lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword, string lpDisplayName);
        [DllImport("advapi32.dll")]
        public static extern bool ChangeServiceConfig2(IntPtr hService, InfoLevel dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo);
        [DllImport("advapi32.dll")]
        public static extern bool ChangeServiceConfig2(IntPtr hService, InfoLevel dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_FAILURE_ACTIONS lpInfo);
        [DllImport("advapi32.dll")]
        public static extern bool CloseServiceHandle(IntPtr hSCObject);
        [DllImport("advapi32.dll")]
        public static extern bool ControlService(IntPtr hService, ServiceControlType dwControl, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_STATUS lpServiceStatus);
        [DllImport("kernel32.dll")]
        public static extern void CopyMemory(IntPtr dst, SC_ACTION[] src, int length);
        [DllImport("advapi32.dll")]
        public static extern IntPtr CreateService(IntPtr hSCManager, string lpSvcName, string lpDisplayName, ServiceControlManagerType dwDesiredAccess, ServiceType dwServiceType, ServiceStartType dwStartType, ServiceErrorControl dwErrorControl, string lpPathName, string lpLoadOrderGroup, int lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword);
        [DllImport("advapi32.dll")]
        public static extern int DeleteService(IntPtr hService);
        [DllImport("advapi32.dll")]
        public static extern IntPtr LockServiceDatabase(IntPtr hSCManager);
        [DllImport("advapi32.dll")]
        public static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, ServiceControlManagerType dwDesiredAccess);
        [DllImport("advapi32.dll")]
        public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ACCESS_TYPE dwDesiredAccess);
        [DllImport("advapi32.dll")]
        public static extern bool QueryServiceConfig(IntPtr hService, IntPtr config, int cbBufSize, ref int pcbBytesNeeded);
        [DllImport("advapi32.dll")]
        public static extern bool QueryServiceStatusEx(IntPtr hService, ServiceStatusType statusType, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_STATUS_PROCESS lpBuffer, int cbBufSize, ref int pcbBytesNeeded);
        [DllImport("advapi32.dll")]
        public static extern int StartService(IntPtr hService, int dwNumServiceArgs, string lpServiceArgVectors);
        [DllImport("advapi32.dll")]
        public static extern bool UnlockServiceDatabase(IntPtr hSCManager);

        // Nested Types
        public enum ACCESS_TYPE
        {
            SERVICE_ALL_ACCESS = 0xf01ff,
            SERVICE_CHANGE_CONFIG = 2,
            SERVICE_ENUMERATE_DEPENDENTS = 8,
            SERVICE_INTERROGATE = 0x80,
            SERVICE_PAUSE_CONTINUE = 0x40,
            SERVICE_QUERY_CONFIG = 1,
            SERVICE_QUERY_STATUS = 4,
            SERVICE_START = 0x10,
            SERVICE_STOP = 0x20,
            SERVICE_USER_DEFINED_CONTROL = 0x100
        }

        public enum InfoLevel
        {
            SERVICE_CONFIG_DESCRIPTION = 1,
            SERVICE_CONFIG_FAILURE_ACTIONS = 2
        }

        [StructLayout(LayoutKind.Sequential)]
        public class QUERY_SERVICE_CONFIG
        {
            public int dwServiceType;
            public int dwStartType;
            public int dwErrorControl;
            public string lpBinaryPathName;
            public string lpLoadOrderGroup;
            public int dwTagId;
            public string lpDependencies;
            public string lpServiceStartName;
            public string lpDisplayName;
            public QUERY_SERVICE_CONFIG() { }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SC_ACTION
        {
            public InstallerAPI.SC_ACTION_TYPE SCActionType;
            public int Delay;
        }

        public enum SC_ACTION_TYPE
        {
            SC_ACTION_NONE,
            SC_ACTION_RESTART,
            SC_ACTION_REBOOT,
            SC_ACTION_RUN_COMMAND
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SERVICE_DESCRIPTION
        {
            public string lpDescription;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SERVICE_FAILURE_ACTIONS
        {
            public int dwResetPeriod;
            public string lpRebootMsg;
            public string lpCommand;
            public int cActions;
            public int lpsaActions;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SERVICE_STATUS
        {
            public int dwServiceType;
            public int dwCurrentState;
            public int dwControlsAccepted;
            public int dwWin32ExitCode;
            public int dwServiceSpecificExitCode;
            public int dwCheckPoint;
            public int dwWaitHint;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SERVICE_STATUS_PROCESS
        {
            public int dwServiceType;
            public int dwCurrentState;
            public int dwControlsAccepted;
            public int dwWin32ExitCode;
            public int dwServiceSpecificExitCode;
            public int dwCheckPoint;
            public int dwWaitHint;
            public int dwProcessID;
            public int dwServiceFlags;
        }

        public enum ServiceControlAccepted
        {
            SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x20,
            SERVICE_ACCEPT_NETBINDCHANGE = 0x10,
            SERVICE_ACCEPT_PARAMCHANGE = 8,
            SERVICE_ACCEPT_PAUSE_CONTINUE = 2,
            SERVICE_ACCEPT_POWEREVENT = 0x40,
            SERVICE_ACCEPT_SESSIONCHANGE = 0x80,
            SERVICE_ACCEPT_SHUTDOWN = 4,
            SERVICE_ACCEPT_STOP = 1
        }

        public enum ServiceControlManagerType
        {
            SC_MANAGER_ALL_ACCESS = 0xf003f,
            SC_MANAGER_CONNECT = 1,
            SC_MANAGER_CREATE_SERVICE = 2,
            SC_MANAGER_ENUMERATE_SERVICE = 4,
            SC_MANAGER_LOCK = 8,
            SC_MANAGER_MODIFY_BOOT_CONFIG = 0x20,
            SC_MANAGER_QUERY_LOCK_STATUS = 0x10
        }

        public enum ServiceControlType
        {
            SERVICE_CONTROL_CONTINUE = 3,
            SERVICE_CONTROL_DEVICEEVENT = 11,
            SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
            SERVICE_CONTROL_INTERROGATE = 4,
            SERVICE_CONTROL_NETBINDADD = 7,
            SERVICE_CONTROL_NETBINDDISABLE = 10,
            SERVICE_CONTROL_NETBINDENABLE = 9,
            SERVICE_CONTROL_NETBINDREMOVE = 8,
            SERVICE_CONTROL_PARAMCHANGE = 6,
            SERVICE_CONTROL_PAUSE = 2,
            SERVICE_CONTROL_POWEREVENT = 13,
            SERVICE_CONTROL_SESSIONCHANGE = 14,
            SERVICE_CONTROL_SHUTDOWN = 5,
            SERVICE_CONTROL_STOP = 1
        }

        public enum ServiceErrorControl
        {
            msidbServiceInstallErrorControlVital = 0x8000,
            SERVICE_ERROR_CRITICAL = 3,
            SERVICE_ERROR_IGNORE = 0,
            SERVICE_ERROR_NORMAL = 1,
            SERVICE_ERROR_SEVERE = 2,
            SERVICEERRORCONTROL_NO_CHANGE = -1
        }

        public enum ServiceStartType
        {
            SERVICE_AUTO_START = 2,
            SERVICE_BOOT_START = 0,
            SERVICE_DEMAND_START = 3,
            SERVICE_DISABLED = 4,
            SERVICE_SYSTEM_START = 1,
            SERVICESTARTTYPE_NO_CHANGE = -1
        }

        public enum ServiceState
        {
            SERVICE_NONE,
            SERVICE_STOPPED,
            SERVICE_START_PENDING,
            SERVICE_STOP_PENDING,
            SERVICE_RUNNING,
            SERVICE_CONTINUE_PENDING,
            SERVICE_PAUSE_PENDING,
            SERVICE_PAUSED
        }

        public enum ServiceStateRequest
        {
            SERVICE_ACTIVE = 1,
            SERVICE_INACTIVE = 2,
            SERVICE_STATE_ALL = 3
        }

        public enum ServiceStatusType
        {
            SC_STATUS_PROCESS_INFO
        }

        public enum ServiceType
        {
            SERVICE_FILE_SYSTEM_DRIVER = 2,
            SERVICE_INTERACTIVE_PROCESS = 0x100,
            SERVICE_KERNEL_DRIVER = 1,
            SERVICE_WIN32_OWN_PROCESS = 0x10,
            SERVICE_WIN32_SHARE_PROCESS = 0x20,
            SERVICETYPE_NO_CHANGE = -1
        }
    }
}
